package com.kingyea.mobilepolice.zuul.config;

import com.alibaba.fastjson.JSON;
import com.kingyea.mobilepolice.zuul.utils.Result;
import com.kingyea.mobilepolice.zuul.utils.StateCode;
import com.netflix.client.ClientException;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 过滤器间的协调,过滤器没有直接的方式来访问对方。
 * 它们可以使用RequestContext共享状态，这是一个类似Map的结构，具有一些显式访问器方法用于被认为是Zuul的原语，内部是使用ThreadLocal实现的
 *
 * @author Mr.Lin
 * @version v1.0.0
 * @description
 * @date Created in 2018/2/2 16:10
 */
@Configuration
@Component
public class ErrorFilter extends ZuulFilter {
    public static final String DEFAULT_ERR_MSG = "系统繁忙,请稍后再试";
    private static final String ERROR_STATUS_CODE_KEY = "error.status_code";// error.status_code参数就是SendErrorFilter过滤器用来判断是否需要执行的重要参数。
    private static final String ERROR_EXCEPTION_KEY = "error.exception";
    private static final String ERROR_MESSIG_KEY = "error.message";
    private String charsetName = "UTF-8";
    private Logger log = LoggerFactory.getLogger(ErrorFilter.class);
    @Value("${kingyea.mobilepolice.security.isEnableSecurity}")
    private Boolean isEnableSecurity;

    /**
     * pre：可以在请求被路由之前调用
     * route：在路由请求时候被调用
     * post：在route和error过滤器之后被调用
     * error：处理请求时发生错误时被调用
     *
     * @param
     * @return java.lang.String
     * @author Mr.Lin
     * @date 2018/4/3 23:06
     */
    @Override
    public String filterType() {
        return "error";
    }

    /**
     * 通过int值来定义过滤器的执行顺序
     *
     * @param
     * @return int
     * @author Mr.Lin
     * @date 2018/4/3 23:07
     */
    @Override
    public int filterOrder() {
        return -1;
    }

    /**
     * 返回一个boolean类型来判断该过滤器是否要执行，所以通过此函数可实现过滤器的开关。
     *
     * @param
     * @return boolean
     * @author Mr.Lin
     * @date 2018/4/3 23:07
     */
    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
//        return ctx.containsKey(ERROR_STATUS_CODE_KEY)||ctx.get("throwable")!=null;
        return true;
    }

    /**
     * 过滤器的具体逻辑。
     * 需要注意，这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求，不对其进行路由，
     * 然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码
     *
     * @param
     * @return java.lang.Object
     * @author Mr.Lin
     * @date 2018/4/3 23:07
     */
    @Override
    public Object run() {
        System.out.println(isEnableSecurity);
        RequestContext ctx = RequestContext.getCurrentContext();

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        try {
            HttpServletRequest request = ctx.getRequest();
            HttpServletResponse response = ctx.getResponse();
            request.setCharacterEncoding(charsetName);
            response.setCharacterEncoding(charsetName);
            response.setContentType("application/json;charset=utf-8");// 解决乱码
            System.out.println(ctx.get(ERROR_STATUS_CODE_KEY));
            System.out.println(ctx.get(ERROR_MESSIG_KEY));
            System.out.println(ctx.get(ERROR_EXCEPTION_KEY));
            Object exception = ctx.get("throwable");
            if (exception != null) {
                if (exception instanceof Exception) {
                    Throwable throwable = (Throwable) exception;
//                    throwable.printStackTrace();
                    Throwable originException = getOriginException(throwable);
                    if (originException instanceof ClientException && originException.getLocalizedMessage().contains("Load balancer does not have available server for client")) {
                        Result result = new Result(StateCode.SERVER_MISSING_ERROR);
                        result.setData(originException.getLocalizedMessage());
                        response.getOutputStream().write(JSON.toJSONString(result).getBytes(charsetName));
                    } else {
                        response.getOutputStream().write(JSON.toJSONString(Result.getFailedResult(originException.getLocalizedMessage())).getBytes(charsetName));
                    }
                }
            } else {

                response.getOutputStream().write(JSON.toJSONString(Result.getFailedResult("系统错误")).getBytes(charsetName));
            }
            response.getOutputStream().flush();
            response.getOutputStream().close();
        } catch (Throwable e) {
            String error = " >>> >>> Error during filtering[ErrorFilter]";
            log.error(error, e);
            try {
                ctx.getResponse().setCharacterEncoding(charsetName);
                ctx.getResponse().setContentType("application/json;charset=utf-8");
                ctx.getResponse().getOutputStream().write(JSON.toJSONString(Result.getFailedResult("系统错误")).getBytes(charsetName));
                ctx.getResponse().getOutputStream().flush();
                ctx.getResponse().getOutputStream().close();
            } catch (Throwable e1) {
                e1.printStackTrace();
            }
        }
        return null;

    }

    private Throwable getOriginException(Throwable e) {
        e = e.getCause();
        while (e.getCause() != null) {
            e = e.getCause();
        }
        return e;
    }
}
